package org.callisto.gui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import org.callisto.EventType;
import org.callisto.Globals;
import org.callisto.StatisticType;
import org.callisto.model.Event;
import org.callisto.model.Keyboard;

public class Gauge extends Widget {
	private static final long serialVersionUID = 1L;
	float needleScale = 0.4f;
	float angleRange = 180;
	float needleRootX;
	float needleRootY;
	int gaugeTickLabelPad = 30;
	float gaugeMin;
	float gaugeMax;
	
	public Gauge(Keyboard keyboard, EventType eventType, int size) {
		super(keyboard, eventType, size, size);
		needleRootX = width * (1-padFactor)/2 + activeWidth/2;
		needleRootY = height * (1-padFactor)/2 + activeHeight/2;
		initialize();
	}
	
	private void initialize() {
		setLayout(new FlowLayout());
		setBackground(new Color(0x40,0x40,0x40));
	}

	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2 = (Graphics2D) g;
		g2.setColor(Color.WHITE);
		g2.setStroke(new BasicStroke(2));
		g2.setRenderingHint(
				RenderingHints.KEY_ANTIALIASING,
	             RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setRenderingHint(
		        RenderingHints.KEY_TEXT_ANTIALIASING,
		        RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
		// ***
		Arc2D arc = new Arc2D.Float(
				width * (1-padFactor)/2,
				height * (1-padFactor)/2,
				(float) activeWidth,
				(float) activeHeight,
				(90-angleRange/2),
				angleRange,
				Arc2D.CHORD);
		g2.draw(arc);
		
		Event lastEvent = keyboard.getLastEvent(eventType);
		if (lastEvent != null) {
			float currentMeasure = lastEvent.getMeasure();
			float minMeasure = keyboard.getMeasureStatistic(eventType, StatisticType.MIN);
			float maxMeasure = keyboard.getMeasureStatistic(eventType, StatisticType.MAX);
			float meanMeasure = keyboard.getMeasureStatistic(eventType, StatisticType.MEAN);
			float medianMeasure = keyboard.getMeasureStatistic(eventType, StatisticType.MEDIAN);
			gaugeMin = 0f;
			gaugeMax = maxMeasure * 1.3f;
			drawNeedle(g2, currentMeasure, 0.8f, Color.WHITE); 
			drawNeedle(g2, minMeasure, 1.0f, Color.GREEN);
			drawNeedle(g2, maxMeasure, 1.0f, Color.RED);
			drawNeedle(g2, medianMeasure, 0.7f, Color.YELLOW);
			drawNeedle(g2, meanMeasure, 0.5f, Color.ORANGE);
			drawGaugeTickLabels(g2, 5);
			Globals.logln(
					String.format("currrent=%.0f, (min,max,mean,median)=(%.0f,%.0f,%.2f,%.2f)\n",
					currentMeasure, minMeasure, maxMeasure, meanMeasure, medianMeasure)
					);
		}
	}

	private void drawGaugeTickLabels(Graphics2D g2, int tickCount) {
		drawTickLabel(g2, gaugeMin, 1.0f, Color.WHITE);
		drawTickLabel(g2, gaugeMax, 1.0f, Color.WHITE);
		float range = gaugeMax - gaugeMin;
		for (int i=1; i<tickCount; i++) {
			float tickValue = gaugeMin + range * i / tickCount;
			drawTickLabel(g2, tickValue, 1.0f, Color.WHITE);
		}
	}
	
	private void drawTickLabel(Graphics2D g2, float measure, float size, Color color) {
		float angle = (float) (
				(
						angleRange * (measure / gaugeMax) + (360 - angleRange)/2
				) * (Math.PI/180)
		);
		float scale = 0.8f * size * (activeWidth + activeHeight)/4;
		Point2D.Float po = new Point2D.Float(1f,0f); // origin
		AffineTransform xfms[] = {
			AffineTransform.getRotateInstance(angle),
			AffineTransform.getQuadrantRotateInstance(1),
			AffineTransform.getScaleInstance(scale,scale),
			AffineTransform.getTranslateInstance(needleRootX, needleRootY)
		};
		Point2D.Float pf = (Point2D.Float) po.clone();
		for (int i=0; i<xfms.length; i++) {
			xfms[i].transform(pf, pf);
		}
		String label = String.format("%.0f",measure);
		Font font = new Font("Arial",Font.PLAIN,10);
		// OFFSET
		FontMetrics fm = g2.getFontMetrics(font);
		int labelOffset = fm.stringWidth(label) * 3 / 3;
		byte factor = (byte) ((angle > Math.PI / 2) ? 0 : 50);
		System.out.println("pf0: " + pf);
		System.out.println("measure: " + measure + ", max: " + gaugeMax + ", angle: " + angle + ", factor: " + factor + ", offset: " + labelOffset);
		AffineTransform.getTranslateInstance(factor * labelOffset, 0).transform(pf, pf);
		System.out.println("pf1: " + pf);
		// OFFSET
		g2.setColor(color);
		g2.setFont(font);
		g2.drawString(label,pf.x,pf.y);
	}

	private void drawNeedle(Graphics2D g2, float measure, float size, Color color) {
		float angle = (float) (Math.PI * ( 1 + measure / gaugeMax));
		float tipX = (float) (needleRootX + width * needleScale * size * Math.cos(angle));
		float tipY = (float) (needleRootY + height * needleScale * size * Math.sin(angle));
		g2.setColor(color);
		g2.draw(new Line2D.Float(needleRootX,needleRootY,tipX,tipY));
		//Globals.logln(String.format("(measure,max,angle,color)=(%.2f,%.2f,%.2f,%s)\n",measure,gaugeMax,angle,color));
	}
}
